package com.googlecode.skald.client.comm;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.core.client.JsonUtils;
import com.googlecode.skald.client.affordances.Affordance;
import com.googlecode.skald.client.affordances.InvalidFormatException;
import com.googlecode.skald.client.affordances.JsAffordance;

/**
 * A JavasScript overlay object for the JSON object that forms the footer
 * of a response from the game server. 
 * See {@link com.googlecode.skald.client.Server#handleResponse(String)}.
 * <p>
 * Currently supported fields in the single JSON header object include:
 * <ul>
 * <li>affordances - an array of {@link JsAffordance} objects.
 * <li>affordances - an array of String names
 * </ul>
 * 
 * @author Zach Tomaszewski
 */
public final class ResponseFooter extends JavaScriptObject {

// TODO: gameOver: true/false field in in footer
// Gives the definitive indication that the game has ended, 
// allowing the UI to respond appropriately... (which means doing what?)  
  
  protected ResponseFooter() {    
  }
  
  /** 
   * Returns the JsArray of all the affordances supported by the current
   * game state.  Will be an empty array if there is no affordances field to read.
   * 
   * @throws ClassCastException  If parses into valid JSON, but not an array.
   */
  public final native JsArray<JsAffordance> affordances() /*-{
    return (this.affordances) ? this.affordances : [];
  }-*/;

  /** 
   * Returns the JsArray of all the object names supported by the current
   * game state.  Will be an empty array if there is no objects field to read.
   * 
   * @throws ClassCastException  If parses into valid JSON, but not an 
   * array of Strings.
   */
  public final native JsArrayString objects() /*-{
    return (this.objects) ? this.objects : [];
  }-*/;
  
  /**
   * Returns the contained affordances as a list.  If there is no affordances
   * field, returns an empty list.
   * 
   * @throws InvalidFormatException If the underlying JsArray is invalid.
   */
  public List<Affordance> getAffordances() throws InvalidFormatException {
    try {
      return JsAffordance.toAffordances(this.affordances());
    }catch (ClassCastException e) {
      throw new InvalidFormatException("affordances field of footer " +
      		"is invalidly formatted", e);
    }
  }
  
  /**
   * Rreturns the contained object names.  If no objects field was given,
   * returns an empty list.
   * 
   * @throws InvalidFormatException  If underlying JsArray is invalid.
   */
  public List<String> getObjects() throws InvalidFormatException {
    try {
      JsArrayString objs = this.objects();
      List<String> list = new ArrayList<String>(objs.length());
      for (int i = 0; i < objs.length(); i++) {
        list.add(objs.get(i));
      }
      return list;
    }catch (Exception e) {
      //JavaScriptException, ClassCast, and others from gwt.dev.shell
      throw new InvalidFormatException(e);
    }
  }
  
  /**
   * Constructs an overlay for the given json object taken from a server 
   * response body.  
   * 
   * @throws IllegalArgumentException  If string cannot be parsed into a 
   * valid JSON object or array.
   */
  public static ResponseFooter parse(String json) {
    return JsonUtils.safeEval(json);
  }
  
}
